package com.neko.seed.auth.annotation.resolver;

import com.neko.seed.auth.annotation.Auth;
import com.neko.seed.auth.enums.TokenSubject;
import com.neko.seed.auth.exception.AuthException;
import com.neko.seed.auth.exception.DisableException;
import com.neko.seed.auth.exception.TokenException;
import com.neko.seed.auth.exception.UnauthorizedException;
import com.neko.seed.auth.service.TokenService;

import com.neko.seed.api.data.enums.UserStatus;
import com.neko.seed.api.entity.User;
import com.neko.seed.api.service.UserService;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

/**
 * 认证注解参数解析器
 *
 * @author Li Jinhui
 * @since 2018/12/7
 */
public class AuthMethodArgumentResolver implements HandlerMethodArgumentResolver {

    @Autowired
    private TokenService tokenService;
    @Autowired
    private UserService userService;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // @Auth注解默认的参数类型为Long，请根据实际需求修改类型
        return parameter.getParameterType().isAssignableFrom(String.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        
        // 从Header取出AccessToken
        String paramToken = webRequest.getParameter("token");
        String headerToken = webRequest.getHeader("X-Token");
        String token = StringUtils.isNotEmpty(paramToken) ? paramToken : headerToken;
        // 判断Token是否为空
        if (StringUtils.isNotEmpty(token)) {
            try {
                // 从Token中获取Id并捕获异常
                String id = String.valueOf(tokenService.parse(TokenSubject.ACCESS, token).getBody().get("id"));

                User user = userService.getById(id);
                if(user == null) {
                    throw new AuthException();
                }
                return id;
            } catch (TokenException e) {
                // Token失效，抛出认证异常
                throw new AuthException();
            } catch (DisableException e) {
                // 账号已禁用
                throw e;
            }
        } else if (!parameter.getParameterAnnotation(Auth.class).required()) {
            // Token为空，判断Token是否可以为空
            return null;
        } else {
            // Token不能为空，抛出未登录异常
            throw new UnauthorizedException();
        }
    }

}
